home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / comm / tcp / Amster.lha / Amster_Install / Source / download.c < prev    next >
C/C++ Source or Header  |  2000-07-31  |  21KB  |  847 lines

  1. /*
  2. ** Download
  3. */
  4.  
  5. #include "include/config.h"
  6.  
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10.  
  11. #include <proto/exec.h>
  12. #include <proto/socket.h>
  13. #include <proto/dos.h>
  14. #include <proto/asl.h>
  15. #include <exec/memory.h>
  16. #include <libraries/dos.h>
  17. #include <libraries/asl.h>
  18. #include <netdb.h>
  19. #include <sys/time.h>
  20. #include <sys/socket.h>
  21. #include <sys/ioctl.h>
  22. #include <netinet/tcp.h>
  23. #include <bsdsocket/socketbasetags.h>
  24. #include <error.h>
  25. #include <time.h>
  26.  
  27. #include "include/mui.h"
  28. #include <MUI/NListview_mcc.h>
  29. #include <MUI/NFloattext_mcc.h>
  30. #include "include/gui.h"
  31. #include "include/rexx.h"
  32. #include "include/panel.h"
  33. #include "include/transfer.h"
  34. #include "include/download.h"
  35. #include "include/prefs.h"
  36. #include "include/share.h"
  37. #include "md5.h"
  38. #include "amster_Cat.h"
  39. #include "include/protos.h"
  40.  
  41.  
  42. int dl_count = 0;
  43. int QueueCount = 0;
  44. int WaitingCount = 0;
  45.  
  46. /* Private functions */
  47.  
  48. ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg);
  49. void dl_startq(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port);
  50. void dl_checkqueue(struct TransferData *data);
  51. void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit);
  52. void PollWaiting(struct TransferData *data, Object *obj);
  53. int dl_filename(songtrans sd);
  54. char *chkmd5_fromlock(BPTR lock);
  55. int dl_askfname(char *fname);
  56. void dl_handlemsg(thread t, int com, APTR data);
  57. void dl_resume(struct TransferData *data);
  58. void dl_cps(struct TransferData *data);
  59. __asm __saveds void dl_sucker(void);
  60.  
  61.  
  62. MUIF dl_dispatch(REG(a0) struct IClass *cl,REG(a2) Object *obj,REG(a1) Msg msg)
  63. {
  64.     struct TransferData *data;
  65.  
  66.     switch(msg->MethodID) {
  67.         case OM_NEW:
  68.             return(dl_new(cl, obj, (APTR)msg));
  69.         case MUIM_Window_Setup:
  70.             return(dl_setup(cl, obj, (APTR)msg));
  71.         case MUIM_Window_Cleanup:
  72.             return(dl_muicleanup(cl, obj, (APTR)msg));
  73.         case DL_ADD:
  74.             data = INST_DATA(cl, obj);
  75.             DoMethod(data->list, MUIM_NList_InsertSingle, (songtrans)(((muimsg)msg)->arg1), MUIV_NList_Insert_Bottom);
  76.             return(NULL);
  77.         case DL_START:
  78.             data = INST_DATA(cl, obj);
  79.             dl_startq(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (u_long)(((muimsg)msg)->arg3), (int)(((muimsg)msg)->arg4));
  80.             return(NULL);
  81.         case DL_UPDATE:
  82.             {
  83.             long pos = MUIV_NList_GetPos_Start;
  84.             data = INST_DATA(cl, obj);
  85.             DoMethod(data->list, MUIM_NList_GetPos, (((muimsg)msg)->arg1), &pos);
  86.             DoMethod(data->list, MUIM_NList_Redraw, pos);
  87.             return(NULL);
  88.             }
  89.         case DL_CPS:
  90.             data = INST_DATA(cl, obj);
  91.             dl_cps(data);
  92.             return(NULL);
  93.         case DL_CLEANUP:
  94.             data = INST_DATA(cl, obj);
  95.             TransferCleanup(data);
  96.             return(NULL);
  97.         case DL_CLEANUP_SINGLE:
  98.             data = INST_DATA(cl, obj);
  99.             TransferCleanupSingle(data, (songtrans)(((muimsg)msg)->arg1));
  100.             return NULL;
  101.         case DL_ABORT:
  102.             data = INST_DATA(cl, obj);
  103.             TransferAbort(data);
  104.             return(NULL);
  105.         case DL_RESUME:
  106.             data = INST_DATA(cl, obj);
  107.             dl_resume(data);
  108.             return(NULL);
  109.         case DL_INFO:
  110.             data = INST_DATA(cl, obj);
  111.             TransferInfo(data);
  112.             return(NULL);
  113.         case DL_PLAY:
  114.             {
  115.             songtrans st;
  116.             data = INST_DATA(cl, obj);
  117.  
  118.             DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &st);
  119.             if (!st) return(NULL);
  120.             if (st->state < DLS_DOWN || !(st->fname)) return(NULL);
  121.             prf_event(PRFE_PLAYMP3, st->fname);
  122.  
  123.             return(NULL);
  124.             }
  125.         case DL_SETERROR:
  126.             data = INST_DATA(cl, obj);
  127.             TransferSetError(data, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
  128.             return(NULL);
  129.         case DL_RETRY:
  130.             data = INST_DATA(cl, obj);
  131.             DownloadRetry(data, obj, (char *)(((muimsg)msg)->arg1), (char *)(((muimsg)msg)->arg2), (int)(((muimsg)msg)->arg3));
  132.             return(NULL);
  133.         case DL_POLLWAIT:
  134.             data = INST_DATA(cl, obj);
  135.             PollWaiting(data, obj);
  136.             return(NULL);
  137.         case DL_REMWAITING:
  138.             data = INST_DATA(cl, obj);
  139.             if (((songtrans)(((muimsg)msg)->arg1))->state == DLS_WAIT) {
  140.                 if (--WaitingCount == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->waitnode);
  141.                 /* This was the last waiting entry - remove input handler */
  142.             }
  143.             return(NULL);
  144.         case DL_SETDELAY:
  145.             data = INST_DATA(cl, obj);
  146.             data->waitnode.ihn_Millis = (int)(((muimsg)msg)->arg1)*1000;
  147.             return(NULL);
  148.         case DL_WATCHER:
  149.             data = INST_DATA(cl, obj);
  150.             TransferWatcher(data);
  151.             return(NULL);
  152.         case DL_COUNTDECREMENT:
  153.             data = INST_DATA(cl, obj);
  154.             if (--dl_count == 0) DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);
  155.             dl_checkqueue(data);
  156.             return(NULL);
  157.         case DL_COUNTINCREMENT:
  158.             data = INST_DATA(cl, obj);
  159.             if (dl_count++ == 0) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);
  160.             return(NULL);
  161.         case DL_CHECKQUEUE:
  162.             data = INST_DATA(cl, obj);
  163.             dl_checkqueue(data);
  164.             return(NULL);
  165.     }
  166.     return(DoSuperMethodA(cl, obj, msg));
  167. }
  168.  
  169.  
  170. ULONG dl_new(struct IClass *cl, Object *obj, struct opSet *msg)
  171. {
  172.     static struct Hook downlistdispHook = { {0,0}, &translistdisp, NULL, NULL };
  173.     struct TransferData *data;
  174.     Object *list, *info, *playbut, *abortbut, *resbut, *cleanbut;
  175.  
  176.     if (obj = (Object *)DoSuperNew(cl, obj,
  177.         MUIA_HelpNode, "download",
  178.         MUIA_Window_Title, MSG_DL_TITLE,
  179.         MUIA_Window_ID, MAKE_ID('D','O','W','N'),
  180.         WindowContents, VGroup,
  181.             Child, list = NListviewObject,
  182.                 MUIA_NListview_NList, NListObject,
  183.                     InputListFrame,
  184.                     MUIA_Font, MUIV_Font_Tiny,
  185.                     MUIA_NList_Title, TRUE,
  186.                     MUIA_NList_Format, "BAR, BAR, BAR, BAR, BAR",
  187.                     MUIA_NList_DisplayHook, &downlistdispHook,
  188.                     MUIA_NList_DragSortable, TRUE,
  189.                     MUIA_CycleChain, 1,
  190.                 End,
  191.             End,
  192.             Child, info = TextObject,
  193.                 TextFrame,
  194.                 MUIA_Background, MUII_TextBack,
  195.                 MUIA_Text_PreParse, "\33c",
  196.             End,
  197.             Child, HGroup,
  198.                 Child, HGroup,
  199.                     Child, playbut = SimpleButton(MSG_DL_PLAY_GAD),
  200.                     MUIA_ShortHelp, MSG_PLAY_HELP,
  201.                 End,
  202.                 Child, HSpace(4),
  203.                 Child, HGroup,
  204.                     Child, abortbut = SimpleButton(MSG_DL_ABORT_GAD),
  205.                     MUIA_ShortHelp, MSG_ABORT_HELP,
  206.                 End,
  207.                 Child, HGroup,
  208.                     Child, resbut = SimpleButton(MSG_DL_RESUME_GAD),
  209.                     MUIA_ShortHelp, MSG_RESUME_HELP,
  210.                 End,
  211.                 Child, HSpace(4),
  212.                 Child, HGroup,
  213.                     Child, cleanbut = SimpleButton(MSG_DL_CLEANUP_GAD),
  214.                     MUIA_ShortHelp, MSG_CLEANUP_HELP,
  215.                 End,
  216.             End,
  217.         End,
  218.         TAG_MORE, msg->ops_AttrList))
  219.     {
  220.         data = INST_DATA(cl,obj);
  221.         data->list = list;
  222.         data->info = info;
  223.  
  224.         data->ihnode.ihn_Object = obj;
  225.         data->ihnode.ihn_Millis = 1000;
  226.         data->ihnode.ihn_Method = DL_CPS;
  227.         data->ihnode.ihn_Flags  = MUIIHNF_TIMER;
  228.  
  229.         data->waitnode.ihn_Object = obj;
  230.         data->waitnode.ihn_Millis = prf->QueueDelay*1000;    /* Poll interval in milliseconds */
  231.         data->waitnode.ihn_Method = DL_POLLWAIT;
  232.         data->waitnode.ihn_Flags  = MUIIHNF_TIMER;
  233.  
  234.         data->watchnode.ihn_Object = obj;
  235.         data->watchnode.ihn_Millis = 10000;
  236.         data->watchnode.ihn_Method = DL_WATCHER;
  237.         data->watchnode.ihn_Flags  = MUIIHNF_TIMER;
  238.  
  239.         DoMethod(playbut,  MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_PLAY   );
  240.         DoMethod(resbut,   MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_RESUME );
  241.         DoMethod(abortbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_ABORT  );
  242.         DoMethod(cleanbut, MUIM_Notify, MUIA_Pressed, FALSE, obj, 1, DL_CLEANUP);
  243.  
  244.         DoMethod(list, MUIM_Notify, MUIA_NList_EntryClick, MUIV_EveryTime, obj, 1, DL_INFO);
  245.         DoMethod(obj, MUIM_Notify, MUIA_Window_CloseRequest, TRUE, gui->iconpanel, 1, PANEL_CLOSEDL);
  246.  
  247.         return((ULONG)obj);
  248.     }
  249.  
  250.     return(0);
  251. }
  252.  
  253.  
  254. void dl_addq(song s)
  255. /* This is the initial function, called from resultview.c */
  256. {
  257.     songtrans sd;
  258.  
  259.     sd = malloc(sizeof(_songtrans));
  260.     if (!sd) return;
  261.     memset(sd, 0, sizeof(_songtrans));
  262.  
  263.     sd->song = nap_songdup(s);
  264.     if (!sd->song) {
  265.         free(sd);
  266.         return;
  267.     }
  268.  
  269.     sd->size = s->size;
  270.     sd->mynick = prf->user;
  271.     sd->type = TYPE_DOWNLOAD_OUT;
  272.     sd->reqtime = time(NULL);
  273.  
  274.     if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
  275.         sd->state = DLS_QUEUE;
  276.         QueueCount++;
  277.     }
  278.     else {
  279.         sprintf(nap_buf, "\"%s\" \"%s\"", s->user, s->title);
  280.         nap_send(NAPC_FILEINFOREQ);
  281.         sd->state = DLS_PREP;
  282.         DoMethod(gui->dwin, DL_COUNTINCREMENT);
  283.     }
  284.  
  285.     DoMethod(gui->dwin, DL_ADD, sd);
  286. }
  287.  
  288.  
  289. void dl_startq(struct TransferData *data, Object *obj, char *title, char *user, u_long ip, int port)
  290. /* This is the initial function, when the actual download is about to
  291.    take place (acknowledged by server) - called from napster.c (via DL_START) */
  292. {
  293.     u_long tmp;
  294.     songtrans sd;
  295.     long i;
  296.  
  297.     for (i=0; ; i++) {
  298.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  299.         if (!tmp) return;
  300.         sd = (songtrans)tmp;
  301.         if ((sd->state == DLS_PREP || sd->state == DLS_WAIT || sd->state == DLS_QUEUE) && stricmp(user,sd->song->user)==0 && strcmp(title,sd->song->title)==0) break;
  302.     }
  303.  
  304.     if (sd->t) return; /* Already in a thread */
  305.  
  306.     if (!dl_filename(sd)) {
  307.         if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
  308.         else if (sd->state == DLS_QUEUE) QueueCount--;
  309.         else {
  310.             sd->state = DLS_ABORT;
  311.             DoMethod(gui->dwin, DL_COUNTDECREMENT);
  312.         }
  313.         sd->state = DLS_ABORT;
  314.         DoMethod(gui->dwin, DL_UPDATE, sd);
  315.         return;
  316.     }
  317.  
  318.     sd->song->ip = ip;    /* In case of browse result, the IP isn't already there */
  319.  
  320.     sd->ip = ip;
  321.     sd->port = port;
  322.     sd->s = -1;
  323.     sd->oldsize = sd->cur;
  324.  
  325.     if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
  326.  
  327.     if (sd->state == DLS_QUEUE) {
  328.         QueueCount--;
  329.         DoMethod(gui->dwin, DL_COUNTINCREMENT);
  330.     }
  331.     else if (sd->state == DLS_WAIT) {
  332.         DoMethod(gui->dwin, DL_COUNTINCREMENT);
  333.     }
  334.  
  335.     sd->state = DLS_PREP;
  336.  
  337.     sd->t = th_spawn(dl_handlemsg, "Amster downloader", dl_sucker, prf->DownloadTaskPri, sd);
  338.     if (!sd->t) {
  339.         sd->state = DLS_ERROR;
  340.         DoMethod(gui->dwin, DL_UPDATE, sd);
  341.     }
  342. }
  343.  
  344.  
  345. void dl_checkqueue(struct TransferData *data)
  346. {
  347.     u_long tmp;
  348.     songtrans sd;
  349.     long i;
  350.  
  351.     if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) return;
  352.  
  353.     for (i=0; ; i++) {
  354.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  355.         if (!tmp) return;
  356.         sd = (songtrans)tmp;
  357.         if (sd->state == DLS_QUEUE) break;
  358.     }
  359.  
  360.     sd->reqtime = time(NULL);    /* Reset time to avoid watcher timeouts */
  361.  
  362.     sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
  363.     nap_send(NAPC_FILEINFOREQ);
  364.     DoMethod(gui->dwin, DL_COUNTINCREMENT);
  365.     sd->state = DLS_PREP;
  366.     QueueCount--;
  367.  
  368.     DoMethod(gui->dwin, DL_UPDATE, sd);
  369. }
  370.  
  371.  
  372. void DownloadRetry(struct TransferData *data, Object *obj, char *title, char *user, int limit)
  373. /* Called from napster.c when a file cannot be downloaded yet (busy) */
  374. {
  375.     u_long tmp;
  376.     songtrans sd;
  377.     long i;
  378.  
  379.     for (i=0; ; i++) {
  380.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  381.         if (!tmp) return;
  382.         sd = (songtrans)tmp;
  383.         if (sd->state == DLS_PREP && strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0) break;
  384.     }
  385.  
  386.     if (sd->RetryCount >= prf->QueueRetries) return;    /* We've already given up */
  387.     else if (limit == 0) {
  388.         sd->state = DLS_ERROR;
  389.         sd->error = ERROR_TEASER;    /* Queue limit is 0 = file can't be downloaded by anyone */
  390.  
  391.         DoMethod(gui->dwin, DL_COUNTDECREMENT);
  392.     }
  393.     else {
  394.         sd->state = DLS_WAIT;
  395.         sd->ErrorCode = limit;
  396.         WaitingCount++;
  397.  
  398.         if (WaitingCount == 1) DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->waitnode);
  399.         /* This is the first waiting entry - add input handler */
  400.  
  401.         DoMethod(gui->dwin, DL_COUNTDECREMENT);
  402.         /* We consider this queued and let other downloads start */
  403.     }
  404.  
  405.     DoMethod(gui->dwin, DL_UPDATE, sd);
  406. }
  407.  
  408.  
  409. void PollWaiting(struct TransferData *data, Object *obj)
  410. {
  411.     u_long tmp;
  412.     songtrans sd;
  413.     long i;
  414.  
  415.     if (WaitingCount == 0) return;    /* Don't waste time! */
  416.  
  417.     for (i=0; ; i++) {
  418.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  419.         if (!tmp) return;
  420.         sd = (songtrans)tmp;
  421.         if (sd->state == DLS_WAIT && QueueCount == 0) {
  422.             if (sd->RetryCount < prf->QueueRetries) {
  423.                 sprintf(nap_buf,"\"%s\" \"%s\"", sd->song->user, sd->song->title);
  424.                 nap_send(NAPC_FILEINFOREQ);
  425.                 sd->RetryCount++;
  426.             }
  427.             else {    /* We give up! */
  428.                 sd->state = DLS_ERROR;
  429.                 sd->error = ERROR_BUSY;
  430.                 DoMethod(gui->dwin, DL_REMWAITING, sd);
  431.                 DoMethod(gui->dwin, DL_UPDATE, sd);
  432.             }
  433.         }
  434.     }
  435. }
  436.  
  437.  
  438. void dl_resume(struct TransferData *data)
  439. {
  440.     u_long item;
  441.     songtrans sd;
  442.  
  443.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  444.     if (!item) return;
  445.  
  446.     sd = (songtrans)item;
  447.     if (sd->state < DLS_ABORT) return;    /* Can't resume files that's already in progress */
  448.     if (sd->t) return;
  449.  
  450.     if (dl_count >= prf->DownloadQueueLimit && prf->DownloadQueueLimit < 26) {
  451.         sd->state = DLS_QUEUE;
  452.         QueueCount++;
  453.     }
  454.     else {
  455.         sd->reqtime = time(NULL);
  456.         sprintf(nap_buf, "\"%s\" \"%s\"", sd->song->user, sd->song->title);
  457.         nap_send(NAPC_FILEINFOREQ);
  458.         sd->state = DLS_PREP;
  459.         DoMethod(gui->dwin, DL_COUNTINCREMENT);
  460.     }
  461.  
  462.     DoMethod(gui->dwin, DL_UPDATE, sd);
  463. }
  464.  
  465.  
  466. int dl_filename(songtrans sd)
  467. {
  468.     BPTR lock;
  469.     __aligned struct FileInfoBlock fib;
  470.     char md5[80] = "";
  471.     char *fname, temp[108];
  472.     long oldsize=0;
  473.     int way, reqrc;
  474.     char *expl, *choice;
  475.  
  476.     fname = malloc(512);
  477.     if (!fname) return 0;
  478.     strcpy(fname, prf->dlpath);
  479.     strncpy(temp, nap_strippath(sd->song->title), 107);
  480.     AddPart(fname, temp, 511);
  481.  
  482.     if (prf->askfile) {
  483.         if (!dl_askfname(fname)) return 0;
  484.     }
  485.     else {    /* Needs optimization and elegance */
  486.         if (strlen(nap_strippath(sd->song->title)) > prf->NameLength) {
  487.             strcpy(fname+strlen(fname)-strlen(nap_strippath(sd->song->title))-4+prf->NameLength, fname+strlen(fname)-4);
  488.         }
  489.     }
  490.  
  491.     lock = Lock(fname, ACCESS_READ);
  492.     if (!lock) {
  493.         sd->fname = fname;
  494.         sd->cur = 0;
  495.         return(1);
  496.     }
  497.  
  498.     if (Examine(lock, &fib)) {
  499.         oldsize = fib.fib_Size;
  500.         sscanf(fib.fib_Comment, "md5: %[^;]", &md5);
  501.         if (md5[0] == 0 && oldsize >= 300032) strcpy(md5, chkmd5_fromlock(lock));
  502.             else UnLock(lock);
  503.     }
  504.     else UnLock(lock);
  505.  
  506.     if (sd->size <= oldsize) {
  507.         way = 1;
  508.         expl = (char *)MSG_DL_RESBIGSIZE;
  509.         choice = (char *)MSG_DL_OVERCANCEL_GAD;
  510.     }
  511.     else if (md5[0] == 0) {
  512.         way = 0;
  513.         expl = (char *)MSG_DL_NOMD5INFO;
  514.         choice = (char *)MSG_DL_RESUMECANCEL_GAD;
  515.     }
  516.     else if (strcmp(md5,sd->song->md5)!=0) {
  517.         way = 1;
  518.         expl = (char *)MSG_DL_NOMATCH;
  519.         choice = (char *)MSG_DL_OVERCANCEL_GAD;
  520.     }
  521.     else {
  522.         way = 2;
  523.         expl = (char *)MSG_DL_RESMATCH;
  524.         choice = (char *)MSG_DL_RESUMEOVER_GAD;
  525.     }
  526.  
  527.     reqrc = MUI_Request(gui->app, gui->win, 0L,
  528.                         (char *)MSG_DL_RESUME_INFO,
  529.                         choice,
  530.                         (char *)MSG_DL_RESUME_MSG,
  531.                         fname,
  532.                         oldsize,
  533.                         sd->size,
  534.                         md5[0]==0 ? (char*)MSG_DL_NOMD5 : md5,
  535.                         sd->song->md5,
  536.                         expl);
  537.  
  538.     if (reqrc == 0) return(0);
  539.  
  540.     if ((way==0 || way==2) && reqrc == 1) {
  541.         sd->fname = fname;
  542.         sd->cur = oldsize;
  543.         return(1);
  544.     }
  545.  
  546.     if (reqrc == 2) {
  547.         if (dl_askfname(fname)) {
  548.             sd->fname = fname;
  549.             sd->cur = 0;
  550.             return(1);
  551.         }
  552.         else return(0);
  553.     }
  554.  
  555.     sd->cur = 0;
  556.     sd->fname = fname;
  557.     return(1);
  558. }
  559.  
  560.  
  561. char *chkmd5_fromlock(BPTR lock)
  562. {
  563.     APTR buffer;
  564.     BPTR fh;
  565.     int len;
  566.     char md5[33] = "";
  567.  
  568.     md5_state_t state;
  569.     md5_byte_t digest[16];
  570.     int di;
  571.  
  572.     md5_init(&state);
  573.  
  574.     if (fh = OpenFromLock(lock)) {
  575.         if (buffer = AllocMem(300032, MEMF_ANY)) {
  576.  
  577.             len = Read(fh, buffer, 300032);
  578.             if (len > 0) {
  579.                 md5_append(&state, (const md5_byte_t *)buffer, len);
  580.                 md5_finish(&state, digest);
  581.                 for (di = 0; di < 16; ++di)
  582.                     sprintf(md5+di*2, "%02x", digest[di]);
  583.             }
  584.             FreeMem(buffer, 300032);
  585.         }
  586.         Close(fh);
  587.     }
  588.     else UnLock(lock);
  589.  
  590.     return md5;
  591. }
  592.  
  593.  
  594. int dl_askfname(char *fname)
  595. {
  596.     struct FileRequester *freq;
  597.     u_long win;
  598.  
  599.     freq = AllocAslRequestTags(ASL_FileRequest, TAG_DONE);
  600.     if (!freq) return(0);
  601.  
  602.     get(gui->dwin, MUIA_Window_Window, &win);
  603.     if (AslRequestTags(freq,
  604.                     ASLFR_Window, win,
  605.                     ASLFR_TitleText, MSG_DL_SELECTFILE,
  606.                     ASLFR_InitialFile, nap_strippath(fname),
  607.                     ASLFR_InitialDrawer, prf->dlpath,
  608.                     ASLFR_DoSaveMode, TRUE,
  609.                     TAG_DONE)) {
  610.         strcpy(fname, freq->fr_Drawer);
  611.         AddPart(fname, freq->fr_File, 511);
  612.         FreeAslRequest(freq);
  613.         return(1);
  614.     }
  615.     else {
  616.         FreeAslRequest(freq);
  617.         return(0);
  618.     }
  619. }
  620.  
  621.  
  622. void dl_handlemsg(thread t, int com, APTR data)
  623. /* This is the function that receives messages from the download
  624.    thread. It's called when something needs to be done in the
  625.    main thread (i.e. updating the window). */
  626. {
  627.     songtrans sd=(songtrans)t->data;
  628.  
  629.     switch (com) {
  630.         case THC_STARTUP:
  631.             sd->ts = 1;
  632.             nap_sendbuf(NAPC_DLINC, "");
  633.             break;
  634.         case THC_EXIT:
  635.             sd->error = (int)data;
  636.             TransferHandleError(sd);
  637.             sd->ts = 0;
  638.             sd->t = NULL;
  639.             DoMethod(gui->dwin, DL_COUNTDECREMENT);
  640.             nap_sendbuf(NAPC_DLCOMPLETE, "");
  641.             if (sd->state == DLS_FIN && (prf->AutoCleanup == 1 || prf->AutoCleanup == 3)) {
  642.                 DoMethod(gui->dwin, DL_CLEANUP_SINGLE, sd);
  643.                 break;
  644.             }
  645.             break;
  646.         case DLC_STATE:
  647.             sd->state = (int)data;
  648.         case DLC_UPDATE:
  649.             DoMethod(gui->dwin, DL_UPDATE, sd);
  650.             break;
  651.         case DLC_ADDSHARE:
  652.             DoMethod(gui->shwin, SHARE_ADDFILE, sd->song, sd->fname);
  653.             break;
  654.     }
  655. }
  656.  
  657.  
  658. void dl_cps(struct TransferData *data)
  659. {
  660.     songtrans sd;
  661.     u_long item;
  662.     int i;
  663.  
  664.     for (i=0; ; i++) {
  665.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  666.         if (!item) return;
  667.         sd = (songtrans)item;
  668.         if (sd->state == DLS_DOWN) {
  669.             CalculateCps(sd);
  670.             DoMethod(gui->dwin, DL_UPDATE, sd);
  671.         }
  672.     }
  673. }
  674.  
  675.  
  676. /* thread code */
  677.  
  678. __asm __saveds void dl_sucker(void)
  679. {
  680.     thread t;
  681.     songtrans sd;
  682.     struct Library *DosBase;
  683.     struct Library *SocketBase;
  684.     char *buffer;
  685.     long tmp;
  686.     long s;
  687.     thmsg m;
  688.     char cmnt[80];
  689.     int count;
  690.  
  691.     t = thr_init();
  692.     if (!t) return;
  693.     sd = t->data;
  694.  
  695.     if (!InitTransferThread(t, sd)) return;
  696.     sd->RetryCount = 0;
  697.     s = sd->s;
  698.     buffer = sd->buffer;
  699.     DosBase = sd->DosBase;
  700.     SocketBase = sd->SocketBase;
  701.  
  702.     while (1) {
  703.         u_long sigs;
  704.  
  705.         sigs = Wait(sd->nsigm | sd->msigm);
  706.         if (sigs&(sd->msigm)) {
  707.             m = (thmsg)GetMsg(t->port);
  708.             if (m) {
  709.                 if (m->com == THC_EXIT) {
  710.                     sd->state = DLS_ABORT;
  711.                     thr_message(t, DLC_UPDATE, 0);
  712.                     ExitTransferThread(sd, 0);
  713.                     return;
  714.                 }
  715.                 if (!m->isreply) {
  716.                     m->isreply=1;
  717.                     ReplyMsg((struct Message *)m);
  718.                 }
  719.             }
  720.         }
  721.  
  722.         if (sigs&(sd->nsigm)) {
  723.             FD_ZERO(&sd->fds);
  724.             FD_SET(s,&sd->fds);
  725.             sd->tv.tv_sec = 0;
  726.             sd->tv.tv_usec = 0;
  727.  
  728.             switch (sd->state) {
  729.                 case DLS_CON:
  730.                     if (WaitSelect(s+1,NULL,&sd->fds,NULL,&sd->tv,0) != 1) break;
  731.                     {
  732.                         sd->state = DLS_REQ;
  733.                         tmp = 0;
  734.                         IoctlSocket(s, FIONBIO, (char*)&tmp);
  735.                         /* Disable non-blocking I/O to the socket */
  736.                     }
  737.  
  738.                 case DLS_REQ:
  739.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  740.                     {
  741.                         tmp = recv(s, buffer, 1, 0);
  742.                         if (tmp != 1) {
  743.                             sd->ErrorCode = Errno();
  744.                             ExitTransferThread(sd, ERROR_NET);
  745.                             return;
  746.                         }
  747.                         if (buffer[0] != '1') {
  748.                             ExitTransferThread(sd, 29);
  749.                             return;
  750.                         }
  751.                         thr_message(t, DLC_UPDATE, 0);
  752.                         send(s, "GET", 3, 0);
  753.                         sprintf(buffer, "%s \"%s\" %d", sd->mynick, sd->song->title, sd->cur);
  754.                         send(s, buffer, strlen(buffer), 0);
  755.  
  756.                         tmp = recv(s, buffer, 32, 0);
  757.                         if (tmp < 1) {
  758.                             sd->ErrorCode = Errno();
  759.                             ExitTransferThread(sd, ERROR_NET);
  760.                             return;
  761.                         }
  762.                         buffer[tmp] = '\0';
  763.  
  764.                         if (atoi(buffer) != sd->size) {
  765.                             if (strcmp(buffer, "FILE NOT FOUND") == 0 || strcmp(buffer, "FILE NOT SHARED") == 0) {
  766.                                 ExitTransferThread(sd, ERROR_NOTFOUND);
  767.                                 return;
  768.                             }
  769.                             else if (strcmp(buffer, "INVALID REQUEST") == 0) {
  770.                                 ExitTransferThread(sd, ERROR_INVALIDREQUEST);
  771.                                 return;
  772.                             }
  773.                             ExitTransferThread(sd, 12);
  774.                             return;
  775.                         }
  776.  
  777.                         sd->f = Open(sd->fname, MODE_READWRITE);
  778.                         if (!sd->f) {
  779.                             sd->ErrorCode = IoErr();
  780.                             ExitTransferThread(sd, ERROR_FILEOPEN);
  781.                             return;
  782.                         }
  783.                         sprintf(cmnt, "md5:%s; size:%ld; user:%s", sd->song->md5, sd->size, sd->song->user);
  784.                         SetComment(sd->fname, cmnt);
  785.                         Seek(sd->f, sd->cur, OFFSET_BEGINNING);
  786.                         sd->state = DLS_DOWN;
  787.                         sd->starttime = time(NULL);
  788.                         sd->resumestart = sd->cur;
  789.                         thr_message(t, DLC_UPDATE, 0);
  790.                     }
  791.  
  792.                 case DLS_DOWN:
  793.                     if (WaitSelect(s+1,&sd->fds,NULL,NULL,&sd->tv,0) != 1) break;
  794.                     while (sd->cur < sd->size) {
  795.  
  796.                         tmp = recv(s, buffer, 4096, 0);
  797.                         if (tmp < 1) {
  798.                             sd->ErrorCode = Errno();
  799.                             ExitTransferThread(sd, ERROR_NET);
  800.                             return;
  801.                         }
  802.                         SetIoErr(0L);    /* FWrite doesn't clear IoErr() due to a bug */
  803.                         count = FWrite(sd->f, buffer, 1, tmp);
  804.                         sd->cur += count;
  805.                         if (count != tmp) {
  806.                             sd->ErrorCode = IoErr();
  807.                             ExitTransferThread(sd, ERROR_FILEWRITE);
  808.                             return;
  809.                         }
  810.  
  811.                         m = (thmsg)GetMsg(t->port);
  812.                         if (m) {
  813.                             if (m->com == THC_EXIT) {
  814.                                 thr_message(t, DLC_STATE, (APTR)DLS_ABORT);
  815.                                 ExitTransferThread(sd, 0);
  816.                                 return;
  817.                             }
  818.                             if (!m->isreply) {
  819.                                 m->isreply = 1;
  820.                                 ReplyMsg((struct Message *)m);
  821.                             }
  822.                         }
  823.  
  824.                         FD_ZERO(&sd->fds);
  825.                         FD_SET(s,&sd->fds);
  826.                     }
  827.  
  828.                     sd->state = DLS_FIN;
  829.                     thr_message(t, DLC_UPDATE, 0);
  830.  
  831.                     if ((strlen(sd->song->user)+strlen(sd->host)+9) < 80) sprintf(cmnt, "from %s (@%s)", sd->song->user, sd->host);
  832.                     else sprintf(cmnt, "from %s (@%s)", sd->song->user, Inet_NtoA(sd->song->ip));
  833.                     /* If the hostname is too long for the file comment, we fall back to the IP */
  834.                     SetComment(sd->fname, cmnt);
  835.  
  836.                     if (prf->autoadd) thr_message(t, DLC_ADDSHARE, 0);
  837.  
  838.                     ExitTransferThread(sd, 0);
  839.                     return;
  840.  
  841.             }
  842.         }
  843.     }
  844.  
  845.     ExitTransferThread(sd, 0);
  846. }
  847.